package cn.lamplet.util.kccu;

import java.io.*;
import java.util.ArrayList;
import java.util.Map;

public class OtaBin {
    private String dir;  //id文件目录
    private String idFileName; //id文件名
    File otaFile;
    OutputStream os;
    public static final int otaBinHeadSize = 1280;//256+512+512+8
    public static final double version = 2.3;
    public static int otaBinLength = 0;

    public OtaBin(String dir, String idFileName) {
        this.dir = dir;
        this.idFileName = idFileName;
    }

    public OtaBin() {
    }

    //返回ota文件名
    public String creatBin() {

        ParseId parseId = new ParseId();
        parseId.handleId(dir, idFileName);
        otaFile = new File(dir, idFileName.split("\\.")[0] + ".ota");

        ParseSeg parseSeg = new ParseSeg(dir, parseId.getSegFileName());
        ArrayList<Integer> segList = parseSeg.getSegList();

        ParsePara parsePara = new ParsePara(dir, parseId.getParaFileName());
        ArrayList<Integer> paraList = parsePara.getParaList();

        Hex2bin hex2bin = new Hex2bin(dir, parseId.getHexFileList());
        hex2bin.creatArray(parseSeg.getSegNumber(), parseSeg.getSegList());
        hex2bin.handleHex2bin1();

        int hexFileSize = hex2bin.getHexFileSize();

        byte[] otaBin = new byte[hexFileSize + 1280 + 1];
        hex2bin.getBinArray(otaBin, hexFileSize);

        String canId = parseId.getCanId();
        System.arraycopy(canId.getBytes(), 0, otaBin, 4, canId.length());
        ArrayList<String> hardwareId = parseId.getHardwareId();
        for (int i = 0; i < hardwareId.size(); i++) {
            System.arraycopy(hardwareId.get(i).getBytes(), 0, otaBin, 9 + 15 * i, hardwareId.get(i).length());
        }

        String partNumber = parseId.getPartNumber();
        System.arraycopy(partNumber.getBytes(), 0, otaBin, 159, partNumber.length());


        System.arraycopy(intToByte(parseSeg.getSegNumber()), 0, otaBin, 256, 4);
        for (int i = 0; i < segList.size(); i++) {
            System.out.printf("%#x\n", segList.get(i));
            System.arraycopy(intToByte(segList.get(i)), 0, otaBin, 264 + i * 4, 4);
        }

        for (int i = 0; i < paraList.size(); i++) {
            System.out.printf("%#x\n", paraList.get(i));
            System.arraycopy(shortToByte(paraList.get(i)), 0, otaBin, 256 + 512 + i * 2, 2);

        }

//        System.arraycopy(intToByte(hex2bin.getMinAddr()), 0, otaBin, 1280, 4);
//        System.arraycopy(intToByte(hex2bin.getHexFileSize()), 0, otaBin, 1284, 4);
        System.arraycopy((intToByte(otaBin.length)), 0, otaBin, 0, 4);
        byte crc = crc8_maxim(otaBin, 0, otaBin.length - 1);
        otaBin[otaBin.length - 1] = crc;


//        for (int i = 1280; i < otaBin.length; i++) {
//            System.out.printf("%x ", otaBin[i]);
//            if (i == 1280 + 257) break;
//        }
        try {
            os = new FileOutputStream(otaFile);
            os.write(otaBin);
            os.close();
//            return parseId.getHexFileName() + ".ota";
            return idFileName.split("\\.")[0] + ".ota";

        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }

    }

    public OtaDto createBin(String idFileName, ParseId parseId, Map<String, byte[]> fileToInputStream) {
        ParseSeg parseSeg;
        ParsePara parsePara;
        OtaDto otaDto = new OtaDto();
        // 解析id文件内容
        otaDto.setIdFileName(idFileName);
        // 解析seg文件
        String segFileName = parseId.getSegFileName();
        if (!(segFileName == null || segFileName.equals(""))) {
            parseSeg = new ParseSeg(new ByteArrayInputStream(fileToInputStream.get(segFileName)));
            otaDto.setSegFileName(segFileName);
        } else {
            parseSeg = new ParseSeg();
            parseSeg.calSegs(parseId, fileToInputStream);
        }
        ArrayList<Integer> segList = parseSeg.segList;

        // 解析par文件
        String parFileName = parseId.getParaFileName();
        if (!(parFileName == null || parFileName.equals(""))) {
            if (fileToInputStream.get(parFileName) == null) {
                parsePara = new ParsePara();
            } else {
                parsePara = new ParsePara(new ByteArrayInputStream(fileToInputStream.get(parFileName)));
                otaDto.setParFileName(parFileName);
            }
        } else {
            parsePara = new ParsePara();
        }
        ArrayList<Integer> paraList = parsePara.paraList;

        Hex2bin hex2bin = new Hex2bin();
        hex2bin.creatArray(parseSeg.getSegNumber(), parseSeg.getSegList());
        for (String hexFile : parseId.getHexFileList()) {
            hex2bin.handleHex2bin2(new ByteArrayInputStream(fileToInputStream.get(hexFile)));

        }
        otaDto.setHexFileNames(parseId.getHexFileList());

        int hexFileSize = hex2bin.getHexFileSize();

        byte[] otaBin = new byte[hexFileSize + 1280 + 1];
        hex2bin.getBinArray(otaBin, hexFileSize);

        String canId = parseId.getCanId();
        System.arraycopy(canId.getBytes(), 0, otaBin, 4, canId.length());
        ArrayList<String> hardwareId = parseId.getHardwareId();
        for (int i = 0; i < hardwareId.size(); i++) {
            System.arraycopy(hardwareId.get(i).getBytes(), 0, otaBin, 9 + 15 * i, hardwareId.get(i).length());
        }


        String partNumber = parseId.getPartNumber();
        if (!(partNumber == null || partNumber.equals(""))) {
            System.arraycopy(partNumber.getBytes(), 0, otaBin, 159, partNumber.length());
        }

        int iVersion = (int) (version * 10);
        System.arraycopy(intToByte(iVersion), 0, otaBin, 196, 4);

        String reserve = parseId.getReserve();
        if (!(reserve == null || reserve.equals(""))) {
            System.arraycopy(reserve.getBytes(), 0, otaBin, 200, reserve.length());
        }

        System.arraycopy(intToByte(parseSeg.getSegNumber()), 0, otaBin, 256, 4);
        System.out.println(segList.size() + "*********************************");
        for (int i = 0; i < segList.size(); i++) {
            System.out.printf("%#x\n", segList.get(i));
            System.arraycopy(intToByte(segList.get(i)), 0, otaBin, 264 + i * 4, 4);
        }

        for (int i = 0; i < paraList.size(); i++) {
            System.out.printf("%#x\n", paraList.get(i));
            System.arraycopy(shortToByte(paraList.get(i)), 0, otaBin, 256 + 512 + i * 2, 2);

        }
        System.arraycopy((intToByte(otaBin.length)), 0, otaBin, 0, 4);
        byte crc = crc8_maxim(otaBin, 0, otaBin.length - 1);
        otaBin[otaBin.length - 1] = crc;
        otaDto.setInputStream(new ByteArrayInputStream(otaBin));
        otaDto.setOtaFileName(idFileName.replace(".id", "") + ".ota");
        otaBinLength = otaBin.length;
        return otaDto;
    }

    public ParseId parseIdFile(InputStream inputStream) {
        return new ParseId(inputStream);

    }

    public byte[] intToByte(int num) {
        return new byte[]{(byte) (num & 0xff), (byte) ((num >> 8) & 0xff), (byte) ((num >> 16) & 0xff), (byte) ((num >> 24) & 0xff)};
    }

    public byte[] shortToByte(int num) {
        return new byte[]{(byte) (num & 0xff), (byte) ((num >> 8) & 0xff)};
    }

    //x8+x5+x4+1
    public byte crc8_maxim(byte[] data, int offset, int length) {
        byte i;
        byte crc = 0;        // Initial value
        length += offset;
        for (int j = offset; j < length; j++) {
            crc ^= data[j] & 0xFF;
            for (i = 0; i < 8; i++) {
                if ((crc & 1) == 0)
                    crc = (byte) ((crc & 0xff) >> 1);
                else
                    crc = (byte) (((crc & 0xff) >> 1) ^ 0x8C);
            }
        }
        return crc;
    }
}
